/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * UserManagementDialog.java
 *
 * Created on 10.5.2010, 14:33:35
 */

package pv1682010.gui;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EventObject;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.sql.DataSource;
import javax.swing.JComponent;
import javax.swing.ListSelectionModel;
import javax.swing.SwingWorker;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pv1682010.Database;
import pv1682010.User;
import pv1682010.UserManager;

/**
 *
 * @author Isamaru
 */
public class UserManagementDialog extends javax.swing.JDialog {

    Logger log = LoggerFactory.getLogger(UserManagementDialog.class);

    UserManager um;
    private int selectedUser = -1;
    private boolean updateOn = true;

    /** Creates new form UserManagementDialog */
    public UserManagementDialog(DataSource ds) {
	super();
        um = new UserManager(ds);
	initComponents();
	setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
	deselectUser();
    }

    public UserManagementDialog(Frame parent, DataSource ds) {
	super(parent);
        um = new UserManager(ds);
	initComponents();
	setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
	deselectUser();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jFrame1 = new javax.swing.JDialog();
        jPanel1 = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        userTable = new javax.swing.JTable();
        jPanel2 = new javax.swing.JPanel();
        userUcoField = new javax.swing.JTextField();
        userNameField = new javax.swing.JTextField();
        userAdministratorCheckbox = new javax.swing.JCheckBox();
        userUcoLabel = new javax.swing.JLabel();
        userNameLabel = new javax.swing.JLabel();
        newButton = new javax.swing.JButton();
        deleteButton = new javax.swing.JButton();
        jPanel3 = new javax.swing.JPanel();
        saveButton = new javax.swing.JButton();
        closeButton = new javax.swing.JButton();
        progressBar = new javax.swing.JProgressBar();

        javax.swing.GroupLayout jFrame1Layout = new javax.swing.GroupLayout(jFrame1.getContentPane());
        jFrame1.getContentPane().setLayout(jFrame1Layout);
        jFrame1Layout.setHorizontalGroup(
            jFrame1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        jFrame1Layout.setVerticalGroup(
            jFrame1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );

        userTable.setModel(new UserTableModel(um));
        userTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        jScrollPane1.setViewportView(userTable);
        userTable.getSelectionModel().addListSelectionListener(getSelectionListener());

        java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("pv1682010/gui/translations"); // NOI18N
        userAdministratorCheckbox.setText(bundle.getString("user_admin")); // NOI18N

        userUcoLabel.setText(bundle.getString("user_uco")); // NOI18N

        userNameLabel.setText(bundle.getString("user_name")); // NOI18N

        newButton.setText(bundle.getString("new")); // NOI18N
        newButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newButtonActionPerformed(evt);
            }
        });

        deleteButton.setText(bundle.getString("delete")); // NOI18N
        deleteButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                deleteButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(userAdministratorCheckbox)
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(userNameLabel)
                            .addComponent(userUcoLabel))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 21, Short.MAX_VALUE)
                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                            .addComponent(userUcoField)
                            .addComponent(userNameField, javax.swing.GroupLayout.DEFAULT_SIZE, 134, Short.MAX_VALUE)))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup()
                        .addComponent(newButton, javax.swing.GroupLayout.DEFAULT_SIZE, 91, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, 85, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(userUcoField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(userUcoLabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(userNameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(userNameLabel))
                .addGap(6, 6, 6)
                .addComponent(userAdministratorCheckbox)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 33, Short.MAX_VALUE)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(newButton)
                    .addComponent(deleteButton))
                .addContainerGap())
        );

        //userUcoField.setInputVerifier(verifier);
        userUcoField.addCaretListener(verifier);
        userNameField.addCaretListener(verifier);
        userAdministratorCheckbox.addActionListener(verifier);

        saveButton.setText(bundle.getString("save")); // NOI18N
        saveButton.setEnabled(false);
        saveButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveButtonActionPerformed(evt);
            }
        });

        closeButton.setText(bundle.getString("close")); // NOI18N
        closeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                closeButtonActionPerformed(evt);
            }
        });

        progressBar.setStringPainted(true);
        progressBar.setVisible(false);

        javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
        jPanel3.setLayout(jPanel3Layout);
        jPanel3Layout.setHorizontalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel3Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(progressBar, javax.swing.GroupLayout.DEFAULT_SIZE, 163, Short.MAX_VALUE)
                    .addGroup(jPanel3Layout.createSequentialGroup()
                        .addComponent(saveButton, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(closeButton, javax.swing.GroupLayout.DEFAULT_SIZE, 78, Short.MAX_VALUE)))
                .addContainerGap())
        );
        jPanel3Layout.setVerticalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 92, Short.MAX_VALUE)
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(closeButton)
                    .addComponent(saveButton))
                .addContainerGap())
        );

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 401, Short.MAX_VALUE)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addContainerGap())
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 186, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void newButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newButtonActionPerformed
	ListSelectionModel sm = userTable.getSelectionModel();
	if (sm.isSelectionEmpty()) {
	    if (!(verifyUco() && verifyName())) {
		return;
	    }
	    UserTableModel tm = (UserTableModel) userTable.getModel();
	    Integer uco = Integer.parseInt(userUcoField.getText());	    
	    int rowIndex = tm.newUser(uco, userNameField.getText(), userAdministratorCheckbox.isSelected());
	    sm.setSelectionInterval(rowIndex, rowIndex);
	} else {
	    sm.clearSelection();
	}
    }//GEN-LAST:event_newButtonActionPerformed

    private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveButtonActionPerformed
	UserTableModel tm = (UserTableModel) userTable.getModel();
	this.setEnabled(false);
	setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
	final SwingWorker<List<User>, Void> sw = getSaveSW();
	progressBar.setValue(progressBar.getMinimum());
	progressBar.setVisible(true);
	sw.addPropertyChangeListener(new PropertyChangeListener(){
	    public void propertyChange(PropertyChangeEvent evt) {
		int progress = sw.getProgress();
		progressBar.setValue(progress);
	    }
	});
	sw.execute();
    }//GEN-LAST:event_saveButtonActionPerformed

    private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed
	ListSelectionModel sm = userTable.getSelectionModel();
	if (sm.isSelectionEmpty()) {
	    deselectUser();
	} else {
	    UserTableModel tm = (UserTableModel) userTable.getModel();
	    int rowIndex = sm.getMinSelectionIndex();
	    tm.deleteUser(rowIndex);
	}
    }//GEN-LAST:event_deleteButtonActionPerformed

    private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed
	setVisible(false);
	dispose();
    }//GEN-LAST:event_closeButtonActionPerformed

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
	final DataSource ds = new Database();
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new UserManagementDialog(ds).setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton closeButton;
    private javax.swing.JButton deleteButton;
    private javax.swing.JDialog jFrame1;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JButton newButton;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JButton saveButton;
    private javax.swing.JCheckBox userAdministratorCheckbox;
    private javax.swing.JTextField userNameField;
    private javax.swing.JLabel userNameLabel;
    private javax.swing.JTable userTable;
    private javax.swing.JTextField userUcoField;
    private javax.swing.JLabel userUcoLabel;
    // End of variables declaration//GEN-END:variables

    private ListSelectionListener getSelectionListener() {
	return new ListSelectionListener(){

	    public void valueChanged(ListSelectionEvent e) {
		if (e.getValueIsAdjusting()) {
		    return;
		}
		ListSelectionModel lsm = (ListSelectionModel)e.getSource();
		if (lsm.isSelectionEmpty()) {
		    deselectUser();
		} else {
		    selectUser(lsm.getMinSelectionIndex());
		}
	    }
	};
    }

    private InputVerifierImpl verifier = new InputVerifierImpl();

    private void deselectUser() {
	log.debug("userDeselected");
	selectedUser = -1;
	userNameField.setEnabled(true);
	userNameField.setText(null);
	userUcoField.setEnabled(true);
	userUcoField.setText(null);
	userAdministratorCheckbox.setEnabled(true);
	userAdministratorCheckbox.setSelected(false);
    }

    private void selectUser(int rowIndex) {
	// necessary so that listener doesn't try to update model
	selectedUser = rowIndex;
	updateOn = false;
	log.info("row " + rowIndex + " selected");
	TableModel tm = userTable.getModel();
	Integer uco = (Integer)     tm.getValueAt(rowIndex, 0);
	String name = (String)      tm.getValueAt(rowIndex, 1);
	Boolean isAdmin = (Boolean) tm.getValueAt(rowIndex, 2);
	userNameField.setEnabled(true);
	userNameField.setText(name);
	userUcoField.setEnabled(false);
	userUcoField.setText(uco.toString());
	userAdministratorCheckbox.setEnabled(true);
	userAdministratorCheckbox.setSelected(isAdmin);
	updateOn = true;
    }

    private final static Color LIGHT_PINK = new Color(255,178,178);
    private class InputVerifierImpl implements CaretListener, ActionListener {

	public boolean verify(JComponent input) {
	    if (input.equals(userUcoField)) {
		return verifyUco();
	    }
	    if (input.equals(userNameField)) {
		return verifyName();
	    }
	    return true;
	}

	private boolean color(JComponent c, boolean valid) {
		if (valid) {
		    c.setForeground(Color.black);
		    c.setBackground(Color.white);
		    return true;
		} else {
		    c.setForeground(Color.red);
		    c.setBackground(LIGHT_PINK);
		    return false;
		}
	}

	private void processChange(EventObject e) {
	    boolean valid = true;
	    if (e.getSource().equals(userUcoField)) {
		valid &= verifyUco();
		color(userUcoField, valid);
	    }
	    if (e.getSource().equals(userNameField)) {
		valid &= verifyName();
		color(userNameField, valid);
	    }
	    if (updateOn && valid && selectedUser >= 0) {
		updateUser(selectedUser);
	    }
	    UserTableModel tm = (UserTableModel) userTable.getModel();	    
	    if (tm.changed()) {
		saveButton.setEnabled(true);
	    } else {
		saveButton.setEnabled(false);
	    }
	}

	public void caretUpdate(CaretEvent e) {
	    processChange(e);
	}

	public void actionPerformed(ActionEvent e) {
	    processChange(e);
	}


    }

    private void updateUser(int rowIndex) {
	String name = userNameField.getText();
	Boolean isAdministrator = userAdministratorCheckbox.isSelected();
	((UserTableModel) userTable.getModel()).updateUser(rowIndex, name, isAdministrator);
    }

    private boolean uniqueUco(int uco) {
	int row = ((UserTableModel) userTable.getModel()).getRowByUco(uco);
	log.trace("Uco {} found at row {}", uco, row);
	return ((row == -1)  || (row == selectedUser));
    }

    private boolean verifyUco() {
	try {
	    Integer uco = Integer.parseInt(userUcoField.getText());
	    if (uco <= 0) {
		return false;
	    }
	    if (! uniqueUco(uco)) {
		log.debug("Uco {} already exists", uco);
		return false;
	    }
	    return true;
	} catch (NumberFormatException ex) {
	    log.debug("Uco is invalid");
	}
	return false;
    }

    private boolean verifyName() {
	return (userNameField.getText().length() > 0);
    }

    private SwingWorker<List<User>, Void> getSaveSW() {
	return new SwingWorker<List<User>, Void>(){

	    private final UserTableModel tm = (UserTableModel) userTable.getModel();

	    @Override
	    protected void done() {
		try {
		    tm.setUsers(get());
		} catch (InterruptedException ex) {
		    log.error("Exception thrown! ", ex);
		} catch (ExecutionException ex) {
		    log.error("Exception thrown! ", ex);
		}
		setEnabled(true);
		setCursor(null);
		progressBar.setVisible(false); //turn off the wait cursor
		log.info("Saved to DB!");
	    }

	    @Override
	    protected List<User> doInBackground() throws Exception {
		tm.saveToDb(new ProgressMonitor(){
		    public void progress(int progress) {
			setProgress(progress);
			try {
			    Thread.sleep(200);
			} catch (InterruptedException ex) {
			    log.error("Error!",ex);
			}
		    }
		});
		setProgress(100);
		return um.getUsers();
	    }
	};
    }
}
